﻿using System.Reflection;
using System.Resources;
using System.Web.Mvc;
using Hallenberg.Core;
using Hallenberg.SmartClient.Interfaces;
using Hallenberg.SmartClient.IO;
using Hallenberg.SmartClient.MVC.Services;
using System.Diagnostics.CodeAnalysis;

namespace Hallenberg.SmartClient.MVC
{
    public abstract class MvcSmartClientApplication : System.Web.HttpApplication, ISmartClientApplication
    {
        private BaseSmartClientApplication m_SmartClientApplication = new BaseSmartClientApplication();

        public static WorkItemController GlobalWorkItem { get; private set; }

        ///////////////////////////////////////////////////////////////////////
        // Standard ASP.NET hooks which enables us to set default values per
        // session, and initialize the application.
        ///////////////////////////////////////////////////////////////////////

        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "This method is called by ASP.NET")]
        public void Session_Start()
        {
            MvcSmartClientApplication.GlobalWorkItem.Services.Resolve<ILocalization>().ChangeLanguage(1030);
        }

        ///////////////////////////////////////////////////////////////////////
        // On appliaion start initialize start up sequence to support
        // dependency injection and inversion of control
        ///////////////////////////////////////////////////////////////////////

        public void Application_Start()
        {
            ApplicationStart();
        }

        ///////////////////////////////////////////////////////////////////////
        // Defining abstract methods in the order they are called.
        ///////////////////////////////////////////////////////////////////////

        /// <summary>
        /// The derived class will be responsible for returning an arraycontaining prefixes
        /// of the names of the assemblies to load.
        /// </summary>
        /// <returns>A valid array or null.</returns>
        public abstract string[] ModulesToLoad();

        /// <summary>
        /// The derived class must return the resource managers registered in the system.
        /// </summary>
        /// <returns>A valid array or null.</returns>
        public abstract ResourceManager[] RegisterResourceManagers();

        public abstract void RegisterRoutes();
        public abstract void InitializeApplicationValues();

        ///////////////////////////////////////////////////////////////////////
        // Initializing application.
        ///////////////////////////////////////////////////////////////////////

        public virtual void ApplicationStart()
        {
            ///////////////////////////////////////////////////////////////////
            // Initializing build-in modules and setting the global work item.
            ///////////////////////////////////////////////////////////////////

            WorkItem.ModuleLoader.AutoLoadModules(this, new string[] { "Hallenberg" });

            ///////////////////////////////////////////////////////////////////
            // Load client provided assemblies.
            ///////////////////////////////////////////////////////////////////

            string[] assemblyPrefixes = ModulesToLoad();
            if (assemblyPrefixes != null)
            {
                WorkItem.ModuleLoader.AutoLoadModules(this, assemblyPrefixes);
            }

            ///////////////////////////////////////////////////////////////////
            // Substitute controller factory.
            ///////////////////////////////////////////////////////////////////

            ControllerBuilder.Current.SetControllerFactory(new ControllerFactoryEx());

            ///////////////////////////////////////////////////////////////////
            // Subscribe to start up event and start application.
            ///////////////////////////////////////////////////////////////////

            m_SmartClientApplication.OnRegisterInternalServices += new System.EventHandler<EventArgs<IServiceLocator>>(delegate(object sender, EventArgs<IServiceLocator> args)
                {
                    args.Value.RegisterType<ILocalization, LocalizationHelper>();
                });

            m_SmartClientApplication.ApplicationStart();
            MvcSmartClientApplication.GlobalWorkItem = m_SmartClientApplication.WorkItem;

            ///////////////////////////////////////////////////////////////////
            // Load client provided resource managers.
            ///////////////////////////////////////////////////////////////////

            ResourceManager[] resourceManagers = RegisterResourceManagers();

            if (resourceManagers != null)
            {
                IResourceMapper resourceMapper = this.WorkItem.Services.Resolve<IResourceMapper>();
                foreach (ResourceManager resManager in resourceManagers)
                {
                    resourceMapper.RegisterResourceManager(resManager);
                }
            }

            ///////////////////////////////////////////////////////////////////
            // Tell client its time to register MVC routes.
            ///////////////////////////////////////////////////////////////////

            RegisterRoutes();

            ///////////////////////////////////////////////////////////////////
            // Initialize additional values.
            ///////////////////////////////////////////////////////////////////

            InitializeApplicationValues();
        }

        public virtual void RegisterAssembly(Assembly assembly)
        {
            m_SmartClientApplication.RegisterAssembly(assembly);
        }

        public WorkItemController WorkItem
        {
            get { return m_SmartClientApplication.WorkItem; }
        }

        public virtual string ResolveRelativePath(string relativePath)
        {
            return this.Server.MapPath(relativePath);
        }
    }
}
